Template de Comprovante
O comprovante impresso ao final de uma venda utiliza um modelo padrão do BTG. É possível substituir esse modelo por um SVG customizado, instalado em tempo de execução via client.printer.
A instalação e a remoção do template exigem que o BtgPayClient esteja conectado ao serviço BTG Pay. O processo de conexão está descrito na Configuração.
Instalação do template
import btgpay.client.printer.PrintException
val meuTemplate = """
<svg xmlns="http://www.w3.org/2000/svg" width="384" height="520" viewBox="0 0 384 520">
<rect width="384" height="520" fill="white"/>
<text x="192" y="40" font-size="26" font-weight="bold" text-anchor="middle"
font-family="Roboto">{{merchant_name}}</text>
<text x="192" y="64" font-size="13" text-anchor="middle"
font-family="Roboto">CNPJ {{cnpj}}</text>
<line x1="20" y1="80" x2="364" y2="80" stroke="black" stroke-width="2"/>
<text x="192" y="126" font-size="30" font-weight="bold" text-anchor="middle"
font-family="Roboto">{{amount}}</text>
<text x="20" y="166" font-size="14" font-family="Roboto">{{payment_method}} {{installments_label}}</text>
<text x="20" y="188" font-size="14" font-family="Roboto">{{date}} {{time}}</text>
<text x="20" y="210" font-size="14" font-family="Roboto">{{via_label}}</text>
<g transform="translate(57,240)">{{qr}}</g>
</svg>
"""
lifecycleScope.launch {
client.printer.setReceiptTemplate(meuTemplate)
.onSuccess { Log.i(TAG, "template instalado") }
.onFailure { e ->
val erro = e as PrintException
Log.e(TAG, "template recusado: brn=${erro.brn} msg=${erro.message}")
}
}
A chamada setReceiptTemplate retorna Result<Unit>. Em caso de falha, a exceção é uma PrintException — o mesmo tipo utilizado nas operações de impressão (ver Tratamento de erros). Os erros de validação específicos do template estão listados na seção Validação na instalação.
Para reverter ao modelo padrão do BTG:
client.printer.clearReceiptTemplate()
Persistência
O template vive exclusivamente na memória do processo do serviço. Se o terminal reiniciar, ou se o Android encerrar o processo, o template é perdido e o comprovante volta ao modelo padrão do BTG. Por isso, a reinstalação deve ser feita sempre que o app conectar ao serviço.
O local recomendado para essa reinstalação é o callback onConnected do ConnectionListener, que é chamado tanto na primeira conexão quanto após uma reconexão automática.
client.connect(object : BtgPayClient.ConnectionListener {
override fun onConnected() {
lifecycleScope.launch {
client.printer.setReceiptTemplate(meuTemplate)
}
}
override fun onDisconnected() {
Log.w(TAG, "Serviço desconectado — aguardando reconexão")
}
override fun onBindFailed() {
Log.e(TAG, "Serviço BTG Pay não instalado")
}
override fun onInitFailed(reason: String) {
Log.e(TAG, "Falha na inicialização: $reason")
}
})
Campos disponíveis
O template é um SVG comum. Onde um dado da venda deve aparecer, basta escrever {{nome_do_campo}}. O restante do SVG é renderizado exatamente como escrito.
| Campo | Conteúdo | Exemplo |
|---|---|---|
{{merchant_name}} | Nome do estabelecimento | MERCADO SILVA |
{{cnpj}} | CNPJ formatado | 30.306.294/0001-45 |
{{date}} | Data da transação | 29/09/2026 |
{{time}} | Hora da transação | 19:30 |
{{via_label}} | Qual via | VIA DO CLIENTE |
{{payment_method}} | Meio de pagamento | CREDITO |
{{amount}} | Valor total | R$ 50,00 |
{{installments_label}} | Rótulo de parcelamento | 3X SEM JUROS DE |
{{installment_amount}} | Valor da parcela | R$ 16,67 |
{{qr_url}} | URL do QR, como texto | https://nf.e/abc |
{{qr}} | O QR desenhado, na origem | (posicionar com <g transform>) |
Um campo sem valor na transação é substituído por texto vazio, dispensando verificação prévia.
O {{qr}} é desenhado na origem (0,0) e posicionado com SVG padrão:
<g transform="translate(57,240)">{{qr}}</g>
Elementos SVG suportados
O template aceita qualquer elemento SVG. Os seguintes foram verificados no pipeline de renderização:
<path> (incluindo bezier), <circle>, <ellipse>, <polygon>, <polyline>, <line>, <rect> com rx, transform, gradiente, opacity, clipPath, mask, <pattern>, <use>/<defs>, <textPath> (texto em curva), filtros como feGaussianBlur, stroke-dasharray.
Um template sem nenhum {{campo}} também é aceito — funciona como um desenho puro.
Logo no template
A logo pode ser incluída como data: URI embutida:
<image href="data:image/png;base64,iVBORw0KGgoAAA..." x="92" y="10" width="200" height="60"/>
Ou desenhada em vetor com <path> e <polygon>. Vetor em preto sólido produz melhor resultado em impressão térmica, pois não passa por conversão de meio-tom.
Referência externa é recusada. Tanto href="/sdcard/logo.png" quanto href="https://..." falham na instalação do template. A imagem deve ser embutida em data: URI.
Fontes
O atributo font-family aceita qualquer fonte instalada no terminal. O terminal carrega mais de 200 faces, incluindo Roboto, Noto Serif, DroidSansMono, além de CJK e emoji. Se a fonte solicitada não existir, o texto é renderizado em Roboto.
font-weight: bold funciona. Pesos intermediários (300, 500) resolvem para normal ou negrito, pois apenas essas duas faces são garantidas.
Para itálico, a face deve ser nomeada diretamente:
<text font-family="Noto Serif" font-style="italic">...</text>
Largura e altura
A largura ideal é width="384", correspondente à largura do papel. Se outra largura for usada, o SDK reescala proporcionalmente — um SVG de 1000x400 sai como 384x154.
A altura é livre. Um template de 2000px é impresso inteiro.
Validação na instalação
setReceiptTemplate compila e rasteriza o template com dados de exemplo antes de aceitá-lo. Um SVG malformado falha nessa chamada, não durante uma venda.
| Erro | Causa |
|---|---|
template is N bytes, over the 262144 byte limit | Template acima de 256 KB. |
external reference is not allowed, only data: URIs: X | href para arquivo ou URL. |
unknown placeholder: {{X}} | Nome fora da tabela de campos (erro de digitação). |
unterminated placeholder: missing }} | Faltou fechar o }}. |
unterminated attribute value | Atributo com aspas não fechadas. |
template does not rasterize: X | Não é um SVG válido. |
O erro unknown placeholder existe para detectar erros de digitação na instalação. Sem ele, um {{amont}} sairia impresso como texto literal em todo comprovante a partir daquele momento.
Limites
| Limite | Valor |
|---|---|
| Bytes do template | 256 KB (262.144) |
Timeout de setReceiptTemplate | 15 s |